
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>SpringMVC - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>SpringMVC - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">在MVC架构模式中，模型（Model）、视图（View）和控制器（Controller）各自的核心职责是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">模型（Model）负责管理应用程序的数据和业务逻辑；视图（View）负责将模型的数据展示给用户并接收用户的输入；控制器（Controller）作为模型和视图之间的中介，接收并处理用户请求，然后调度相应的操作。</div>
          </div>
          <div class="card-source">来源: 1.2 MVC架构</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Spring MVC框架中的核心（前端）控制器是什么？它的主要作用是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Spring MVC的核心（前端）控制器是`org.springframework.web.servlet.DispatcherServlet`。它的主要作用是在框架的最前端接收所有请求，并负责整个框架的核心调度管理。</div>
          </div>
          <div class="card-source">来源: 2.2 配置核心(前端)控制器</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在Spring MVC中，如何通过注解将URL路径中的一部分动态值作为参数传递给控制器方法？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可以使用`@PathVariable`注解来接收路径参数。例如，为请求路径`@RequestMapping("/hello/{id}")`定义一个方法，并使用`@PathVariable("id") Integer id`作为形参，即可捕获URL中`id`部分的值。</div>
          </div>
          <div class="card-source">来源: 3.5 路径参数</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">转发（forward）和重定向（redirect）在数据传递和浏览器行为上有何不同？在何种场景下应优先使用重定向？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">转发时，数据在Request作用域内传递，浏览器地址栏不发生变化。重定向时，数据通常需要借助Session作用域传递，浏览器会收到新的URL并重新发起请求，地址栏会更新。在增、删、改操作之后，为了防止用户刷新页面导致请求重复提交，应优先使用重定向。</div>
          </div>
          <div class="card-source">来源: 4.3 跳转细节 & 五、传值</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">在Spring MVC中，`@ResponseBody`和`@RequestBody`这两个注解分别有什么作用？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`@ResponseBody`注解的作用是将控制器方法的返回值（如一个Java对象）转换成JSON格式，并直接写入HTTP响应体中。`@RequestBody`注解的作用是将HTTP请求体中的JSON数据转换成方法参数对应的Java对象。</div>
          </div>
          <div class="card-source">来源: 7.2 使用@ResponseBody & 7.4 使用@RequestBody, 接收Json参数</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">相较于在每个控制器方法中单独处理异常，Spring MVC提供了哪两种更集中的异常处理方案？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Spring MVC提供了两种集中的异常处理方案：1. 实现`HandlerExceptionResolver`接口来自定义一个全局的异常解析器。2. 使用`@ControllerAdvice`注解的类，并在其中定义使用`@ExceptionHandler`注解的方法来统一处理指定类型的异常。</div>
          </div>
          <div class="card-source">来源: 8.2 异常解析器，统一处理 & 8.3 注解实现</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">请描述Spring MVC拦截器（HandlerInterceptor）中`preHandle`、`postHandle`和`afterCompletion`三个方法的执行顺序和时机。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">1. `preHandle`: 在控制器（handler）方法执行之前调用。<br>2. `postHandle`: 在控制器方法执行之后，视图渲染之前调用。<br>3. `afterCompletion`: 在整个请求完成，即页面渲染完毕之后调用，常用于资源回收。</div>
          </div>
          <div class="card-source">来源: 9.1 定义拦截器</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">RESTful是一种什么样的开发风格？请根据文档描述其两个核心优点。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">RESTful是一种软件开发风格，它规定每个资源都有自己的唯一标识（URL），并且每个请求都有明确的动词（HTTP方法，如GET, POST, PUT, DELETE）。其核心优点是：1. 看Url就知道要访问什么资源；2. 看http method就知道要执行什么操作。</div>
          </div>
          <div class="card-source">来源: 11.1 开发风格 & 11.2 优点</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">当`DispatcherServlet`的`url-pattern`被配置为`/`后，为什么会影响静态资源的访问？文档中提到的`<mvc:default-servlet-handler/>`是如何解决这个问题的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">因为`DispatcherServlet`配置为`/`会覆盖掉Tomcat中处理静态资源的默认Servlet。`<mvc:default-servlet-handler/>`的解决方案是：增加一个优先级最低的处理器，如果一个请求没有被任何控制器匹配，该处理器就会将请求转交给Tomcat的默认Servlet来处理，从而使静态资源可以被正常访问。</div>
          </div>
          <div class="card-source">来源: 六、 静态资源 & 6.2 解决方案2</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">Thymeleaf模板引擎的“动静结合”特点具体指的是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">“动静结合”是指Thymeleaf模板文件（.html）既可以直接用浏览器打开查看静态页面效果（浏览器会忽略未定义的Thymeleaf标签属性），也可以通过Web应用程序访问，此时Thymeleaf引擎会动态地替换掉静态内容，使页面动态显示。</div>
          </div>
          <div class="card-source">来源: Thymeleaf简介 & Thymeleaf 的特点</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在整合Spring和Spring MVC时，为什么通常需要配置两个独立的IoC容器（工厂）？它们各自的职责是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">通常会配置两个独立的工厂以实现职责分离。一个是由`ContextLoaderListener`启动的Spring工厂，负责生产除控制器外的所有组件（如Service、DAO等）。另一个是由`DispatcherServlet`启动的Spring MVC工厂，专门负责生产控制器（Controller）及MVC相关的组件。Spring MVC工厂会作为Spring工厂的子工厂，可以访问父工厂中的组件。</div>
          </div>
          <div class="card-source">来源: 13.1 整合思路</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">当使用Jackson处理JSON序列化时，如果想在生成的JSON中忽略值为null的属性，应该在类的属性上添加哪个注解？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">应该在属性上添加`@JsonInclude(JsonInclude.Include.NON_NULL)`注解。这个注解可以使得在生成JSON时，如果该属性的值为null，则不会被输出。</div>
          </div>
          <div class="card-source">来源: 7.5.4 null和empty属性排除</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
